package com.lw.chat.protocol;

import com.lw.chat.config.Config;
import com.lw.chat.message.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

@Slf4j
@ChannelHandler.Sharable
/**
 * 使用了Sharable注解，必须和LengthFieldBasedFrameDecoder一起使用，确保接收到消息是完整的
 */
public class MessageCodecSharable extends MessageToMessageCodec<ByteBuf,Message> {

    /**
     * 出站调用
     * @param ctx
     * @param msg
     * @param outList
     * @throws Exception
     */
    @Override
    protected void encode(ChannelHandlerContext ctx, Message msg, List<Object> outList) throws Exception {
        ByteBuf out = ctx.alloc().buffer();
        out.writeBytes(new byte[]{1,2,3,4});//魔数 4字节
        out.writeByte(1);//版本
        out.writeByte(Config.getSerializerAlgorithm().ordinal());// 序列化算法，0 jdk， 1 json
        out.writeByte(msg.getMessageType());//指令类型
        out.writeInt(msg.getSequenceId());//请求序号 4字节

        out.writeByte(0xff);//无意义，对齐填充用的，因为除去消息正文外，字节长度总值为15，为了凑2^n，所以加一个无意义的字节

//        ByteArrayOutputStream bos = new ByteArrayOutputStream();
//        ObjectOutputStream oos = new ObjectOutputStream(bos);//将对象转换为二进制的字节数组
//        oos.writeObject(msg);
//        byte[] bytes = bos.toByteArray();//对象字节数组
//        oos.close();
        byte[] bytes = Config.getSerializerAlgorithm().serialize(msg);

        out.writeInt(bytes.length);//正文长度 4字节
        out.writeBytes(bytes);//消息正文

        outList.add(out); //将消息传递给下一个Handler，这行代码一定要，否则消息无法正常发送
    }

    /**
     * 入站调用
     * @param ctx
     * @param in
     * @param out
     * @throws Exception
     */
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        int magicNum = in.readInt();//魔数 4字节
        byte version = in.readByte();//版本
        byte serializerType = in.readByte();// 序列化算法，0 jdk， 1 json
        byte messageType = in.readByte();//指令类型
        int sequenceId = in.readInt();//请求序号 4字节

        //无意义的内容就读取忽略就行
        in.readByte();//无意义，对齐填充用的，因为除去消息正文外，字节长度总值为15，为了凑2^n，所以加一个无意义的字节

        int length = in.readInt();//正文长度 4字节

        byte[] bytes = new byte[length];
        in.readBytes(bytes,0,length);//消息正文

        //将字节数组反序列化为对象
        Message msg = null;
        Serializer.Algorithm serializer = Serializer.Algorithm.values()[serializerType];
        Class<?> messageClass = Message.getMessageClass(messageType);
        Object object = serializer.deserialize(messageClass,bytes);
        if(object instanceof Message message){
            msg = message;
        }
        out.add(msg);//为了将消息给下一个Handler使用

        log.debug("{},{},{},{},{},{}",magicNum,version,serializerType,messageType,sequenceId,length);
        log.debug("{}",msg);
    }
}
